]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
authPrompt: support smartcard authentication
authorRay Strode <rstrode@redhat.com>
Thu, 27 Jun 2013 12:54:19 +0000 (08:54 -0400)
committerRay Strode <rstrode@redhat.com>
Mon, 19 Aug 2013 01:22:49 +0000 (21:22 -0400)
This commit detects when a user inserts a smartcard,
and then initiates user verification using the gdm-smartcard
PAM service.

Likewise, if a user removes their smartcard, password verification
(or the user list depending on auth mode and configuration) are initiated

https://bugzilla.gnome.org/show_bug.cgi?id=683437

js/gdm/authPrompt.js
js/gdm/util.js
js/ui/screenShield.js

index 640395afe8f3f598c2610463c6f9f696fe3ab8d3..e3d0ab9d7925ea3e87b1517b60d8c3c7839eebb2 100644 (file)
@@ -60,6 +60,8 @@ const AuthPrompt = new Lang.Class({
         this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
         this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint));
         this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint));
+        this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged));
+        this.smartcardDetected = this._userVerifier.smartcardDetected;
 
         this.connect('next', Lang.bind(this, function() {
                          this.updateSensitivity(false);
@@ -221,6 +223,25 @@ const AuthPrompt = new Lang.Class({
         this.emit('prompted');
     },
 
+    _onSmartcardStatusChanged: function() {
+        this.smartcardDetected = this._userVerifier.smartcardDetected;
+
+        // Most of the time we want to reset if the user inserts or removes
+        // a smartcard. Smartcard insertion "preempts" what the user was
+        // doing, and smartcard removal aborts the preemption.
+        // The exceptions are: 1) Don't reset on smartcard insertion if we're already verifying
+        //                        with a smartcard
+        //                     2) Don't reset if we've already succeeded at verification and
+        //                        the user is getting logged in.
+        if (this._userVerifier.serviceIsDefault(GdmUtil.SMARTCARD_SERVICE_NAME) &&
+            this.verificationStatus == AuthPromptStatus.VERIFYING &&
+            this.smartcardDetected)
+            return;
+
+        if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
+            this.reset();
+    },
+
     _onShowMessage: function(userVerifier, message, styleClass) {
         this.setMessage(message, styleClass);
         this.emit('prompted');
@@ -437,7 +458,23 @@ const AuthPrompt = new Lang.Class({
         if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED)
             this.emit('failed');
 
-        this.emit('reset', BeginRequestType.PROVIDE_USERNAME);
+        let beginRequestType;
+
+        if (this._mode == AuthPromptMode.UNLOCK_ONLY) {
+            // The user is constant at the unlock screen, so it will immediately
+            // respond to the request with the username
+            beginRequestType = BeginRequestType.PROVIDE_USERNAME;
+        } else if (this.smartcardDetected &&
+                   this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
+            // We don't need to know the username if the user preempted the login screen
+            // with a smartcard.
+            beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME;
+        } else {
+            // In all other cases, we should get the username up front.
+            beginRequestType = BeginRequestType.PROVIDE_USERNAME;
+        }
+
+        this.emit('reset', beginRequestType);
     },
 
     addCharacter: function(unichar) {
index a7b8b626d0facc27136ef9f4dcd2d07ff2fee196..7ed50979b19970b6220aa3215e84ca947fa78f18 100644 (file)
@@ -13,16 +13,19 @@ const Fprint = imports.gdm.fingerprint;
 const Main = imports.ui.main;
 const Params = imports.misc.params;
 const ShellEntry = imports.ui.shellEntry;
+const SmartcardManager = imports.misc.smartcardManager;
 const Tweener = imports.ui.tweener;
 
 const PASSWORD_SERVICE_NAME = 'gdm-password';
 const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
+const SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
 const FADE_ANIMATION_TIME = 0.16;
 const CLONE_FADE_ANIMATION_TIME = 0.25;
 
 const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
 const PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication';
 const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
+const SMARTCARD_AUTHENTICATION_KEY = 'enable-smartcard-authentication';
 const BANNER_MESSAGE_KEY = 'banner-message-enable';
 const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
 const ALLOWED_FAILURES_KEY = 'allowed-failures';
@@ -122,6 +125,19 @@ const ShellUserVerifier = new Lang.Class({
         this._updateDefaultService();
 
         this._fprintManager = new Fprint.FprintManager();
+        this._smartcardManager = SmartcardManager.getSmartcardManager();
+
+        // We check for smartcards right away, since an inserted smartcard
+        // at startup should result in immediately initiating authentication.
+        // This is different than fingeprint readers, where we only check them
+        // after a user has been picked.
+        this._checkForSmartcard();
+
+        this._smartcardManager.connect('smartcard-inserted',
+                                       Lang.bind(this, this._checkForSmartcard));
+        this._smartcardManager.connect('smartcard-removed',
+                                       Lang.bind(this, this._checkForSmartcard));
+
         this._messageQueue = [];
         this._messageQueueTimeoutId = 0;
         this.hasPendingMessages = false;
@@ -253,6 +269,28 @@ const ShellUserVerifier = new Lang.Class({
             }));
     },
 
+    _checkForSmartcard: function() {
+        let smartcardDetected;
+
+        if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
+            smartcardDetected = false;
+        else if (this.reauthenticating)
+            smartcardDetected = this._smartcardManager.hasInsertedLoginToken();
+        else
+            smartcardDetected = this._smartcardManager.hasInsertedTokens();
+
+        if (smartcardDetected != this.smartcardDetected) {
+            this.smartcardDetected = smartcardDetected;
+
+            if (this.smartcardDetected)
+                this._preemptingService = SMARTCARD_SERVICE_NAME;
+            else if (this._preemptingService == SMARTCARD_SERVICE_NAME)
+                this._preemptingService = null;
+
+            this.emit('smartcard-status-changed');
+        }
+    },
+
     _reportInitError: function(where, error) {
         logError(error, where);
         this._hold.release();
@@ -310,7 +348,9 @@ const ShellUserVerifier = new Lang.Class({
     },
 
     _getForegroundService: function() {
-        // For now, the foreground service is always the default service
+        if (this._preemptingService)
+            return this._preemptingService;
+
         return this._defaultService;
     },
 
@@ -318,9 +358,15 @@ const ShellUserVerifier = new Lang.Class({
         return serviceName == this._getForegroundService();
     },
 
+    serviceIsDefault: function(serviceName) {
+        return serviceName == this._defaultService;
+    },
+
     _updateDefaultService: function() {
         if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
             this._defaultService = PASSWORD_SERVICE_NAME;
+        else if (this.smartcardDetected)
+            this._defaultService = SMARTCARD_SERVICE_NAME;
         else if (this._haveFingerprintReader)
             this._defaultService = FINGERPRINT_SERVICE_NAME;
     },
index 910462a1f98399047ab689115e39306f199bc045..f375735dc6cfec38a321de7a8dfa8ce55fa28d68 100644 (file)
@@ -25,6 +25,7 @@ const Main = imports.ui.main;
 const Overview = imports.ui.overview;
 const MessageTray = imports.ui.messageTray;
 const ShellDBus = imports.ui.shellDBus;
+const SmartcardManager = imports.misc.smartcardManager;
 const Tweener = imports.ui.tweener;
 const Util = imports.misc.util;
 
@@ -546,6 +547,13 @@ const ScreenShield = new Lang.Class({
 
         this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
 
+        this._smartcardManager = SmartcardManager.getSmartcardManager();
+        this._smartcardManager.connect('smartcard-inserted',
+                                       Lang.bind(this, function(token) {
+                                           if (this._isLocked && token.UsedToLogin)
+                                               this._liftShield(true, 0);
+                                       }));
+
         this._inhibitor = null;
         this._aboutToSuspend = false;
         this._loginManager = LoginManager.getLoginManager();